package com.java.common.base.dao;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.transform.Transformers;
import org.hibernate.type.Type;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.java.common.base.model.PageBean;

/**
 * Title:SpringBaseDao<br>
 * Description:<br>
 * Company: IBM<br>
 * Copyright @ 2012 .All rights reserved. <br>
 * @author Liuhl<br>
 * @version 2008-4-16 1.0
 */
public class SQLBaseDao extends HibernateDaoSupport {

	private static Map<String,Type> columnTypes=new HashMap<String,Type>(Hibernate.class.getFields().length);

	static{
		for (Field field : Hibernate.class.getFields()) {
			Type type=null;
			try {
				type=(Type) field.get(null);
			} catch (IllegalArgumentException e) {
				throw new RuntimeException(e);
			} catch (IllegalAccessException e) {
				throw new RuntimeException(e);
			}
			columnTypes.put(field.getName(), type);
		}		
	}

	/**
	 * SQL数据翻页列表显示(携带查询参数)
	 * @param sql
	 * @param parameters
	 * @param page
	 * @return
	 */
	protected List<?> listBySQL(String sql,String[] returnColumns, Class<?> returnClass, List<?> parameters, PageBean page) {
		final String fSql=sql;
		final String[] fReturnColumns=returnColumns;
		final Class<?> fReturnClass=returnClass;
		final List<?> fParaments=parameters;
		final PageBean fPage=page;
		return getHibernateTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session session)throws HibernateException, SQLException {
				//这里的session会在退出方法时由spring处理，以并决定立即关闭还是延迟关闭。
				//手动写session.close()是无效的，因为这里的ssion是代理类，close()方法是被阻止的。
				SQLQuery query = session.createSQLQuery(fSql);
				//是否有查询参数
				if(fParaments!=null)
					for (int i = 0; i < fParaments.size(); i++) {
						query.setParameter(i, fParaments.get(i));
					}
				//是否需要翻页
				//如果翻页信息存在并且每页数据行不小于0则设置翻页
				if(fPage!=null && fPage.getRowCount()>=0){
					if (fPage.getCount() == 0) {
						fPage.setCount(query.list().size());
					}
					query.setFirstResult(fPage.getStart());
					query.setMaxResults(fPage.getMaxResult());
				}
				//是否需要返回对象
				if(fReturnColumns!=null && fReturnClass!=null){
					for (String column : fReturnColumns) {
						int index = column.indexOf(':');
						if(index==-1){
							query.addScalar(column);
						}else{
							Type type=columnTypes.get(column.substring(index+1).toUpperCase());
							if(type==null)throw new RuntimeException(column.substring(index)+" not in Hibernate constants");
							query.addScalar(column.substring(0,index),type);
						}
					}
					query.setResultTransformer(Transformers.aliasToBean(fReturnClass));
				}
				return query.list();
			}
		});
	}

	/**
	 * 数据翻页列表显示
	 * @param sql
	 * @param page
	 * @return
	 */
	protected List<?> listBySQL(String sql, String[] returnColumns, Class<?> returnClass, PageBean page) {
		return listBySQL(sql, returnColumns, returnClass, new ArrayList<Object>(),page);
	}

	/**
	 * 强制添加countsql的翻页查询
	 * @param sql
	 * @param countSql
	 * @param returnColumns
	 * @param returnClass
	 * @param page
	 * @return
	 */
	protected List<?> listBySQL(String sql, String countSql , String[] returnColumns, Class<?> returnClass, PageBean page) {
		return listBySQL(sql, countSql, returnColumns, returnClass, new ArrayList<Object>(),page);
	}

	/**
	 * 强制添加countSql的翻页查询(携带查询参数)
	 * @param sql
	 * @param countSql
	 * @param returnColumns
	 * @param returnClass
	 * @param parameters
	 * @param page
	 * @return
	 */
	protected List<?> listBySQL(String sql, String countSql , String[] returnColumns, Class<?> returnClass, List<Object> parameters, PageBean page) {
		if (countSql != null)
			page.setCount(countBySQL(countSql,parameters));
		return listBySQL(sql, returnColumns, returnClass, parameters, page);
	}

	/**
	 * 不需要翻页显示的查询(携带参数)
	 * @param sql
	 * @param returnColumns
	 * @param returnClass
	 * @param parameters
	 * @return
	 */
	protected List<?> listBySQL(String sql, String[] returnColumns, Class<?> returnClass, List<?> parameters){
		return listBySQL(sql, returnColumns, returnClass, parameters, null);
	}

	/**
	 * 不需要翻页显示的查询(无查询参数)
	 * @param sql
	 * @param returnColumns
	 * @param returnClass
	 * @return
	 */
	protected List<?> listBySQL(String sql, String[] returnColumns, Class<?> returnClass){
		return listBySQL(sql, returnColumns, returnClass, new ArrayList<Object>());
	}
	/**
	 * SQL数据翻页列表显示(携带查询参数)，返回对象数组
	 * @param sql
	 * @param parameters
	 * @param page
	 * @return 返回对象数组
	 */
	protected List<?> listBySQL(String sql,List<?> parameters, PageBean page) {
		return listBySQL(sql,null, null, parameters, page);
	}

	/**
	 * 数据翻页列表显示，返回对象数组
	 * @param sql
	 * @param page
	 * @return
	 */
	protected List<?> listBySQL(String sql,PageBean page) {
		return listBySQL(sql, new ArrayList<Object>(),page);
	}

	/**
	 * 不需要翻页显示的查询，返回对象数组(携带参数)
	 * @param sql
	 * @param parameters
	 * @return
	 */
	protected List<?> listBySQL(String sql,List<?> parameters){
		return listBySQL(sql, parameters,null);
	}

	/**
	 * 不需要翻页显示的查询，返回对象数组(无查询参数)
	 * @param sql
	 * @return
	 */
	protected List<?> listBySQL(String sql){
		return listBySQL(sql, new ArrayList<Object>());
	}
	/**
	 * 提取单一记录(携带参数)
	 * @param sql
	 * @param parameters
	 * @return
	 */
	protected Object getBySQL(String sql, String[] returnColumns, Class<?> returnClass, List<?> parameters){
		final String fSql=sql;
		final String[] fReturnColumns=returnColumns;
		final Class<?> fReturnClass=returnClass;
		final List<?> fParaments=parameters;
		return getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)throws HibernateException, SQLException {
				SQLQuery query = session.createSQLQuery(fSql);
				if(fParaments!=null)
					for (int i = 0; i < fParaments.size(); i++) {
						query.setParameter(i, fParaments.get(i));
					}
				if(fReturnColumns!=null){
					for (String column : fReturnColumns) {
						int index = column.indexOf(':');
						if(index==-1){
							query.addScalar(column);
						}else{
							Type type=columnTypes.get(column.substring(index+1).toUpperCase());
							if(type==null)throw new RuntimeException(column.substring(index)+" not in Hibernate constants");
							query.addScalar(column.substring(0,index),type);
						}
					}
				}
				query.setResultTransformer(Transformers.aliasToBean(fReturnClass));
				return query.setMaxResults(1).uniqueResult();
			}
		});
	}

	/**
	 * 提取单一记录
	 * @param sql
	 * @return
	 */
	protected Object getBySQL(String sql, String[] returnColumns, Class<?> returnClass){
		return getBySQL(sql, returnColumns, returnClass, new ArrayList<Object>());
	}

	/**
	 * 获得聚合函数值得方法(携带参数)
	 * @param sql
	 * @param parameters
	 * @return
	 */
	protected Object aggregationBySQL(String sql, List<Object> parameters) {
		final String fSql=sql;
		final List<Object> fParaments=parameters;
		return getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)throws HibernateException, SQLException {
				Query query = session.createSQLQuery(fSql);
				if(fParaments!=null)
					for (int i = 0; i < fParaments.size(); i++) {
						query.setParameter(i, fParaments.get(i));
					}
				Object obj=query.setMaxResults(1).uniqueResult();
				if(obj==null)return null;
				//for mysql
				if(obj instanceof BigInteger)
					obj=((BigInteger)obj).intValue();
				else if (obj instanceof BigDecimal)
					obj=((BigDecimal)obj).intValue();
				else//for db2,oracle
					obj=((Object[])obj)[1];
				return obj;
			}
		});
	}

	/**
	 * 计算查询总量
	 * 携带参数
	 * @param sql
	 * @return
	 */
	protected int countBySQL(String sql,List<Object> parameters) {
		Integer result = (Integer) aggregationBySQL(sql,parameters);
		return result.intValue();
	}

	/**
	 * 计算查询总量
	 * 如果查询携带参数请使用protected int count(String sql,List parameters)
	 * @param sql
	 * @return
	 */
	protected int countBySQL(String sql) {
		return countBySQL(sql,new ArrayList<Object>());
	}
	/**
	 * 执行sql语句例如根据条件批量更新或者删除等
	 *
	 * @param sql
	 */
	protected void excuteSQL(String sql) {
		excuteSQL(sql,new ArrayList<Object>());
	}
	/**
	 * 执行sql语句例如根据条件批量更新或者删除等(携带参数)
	 * @param sql
	 * @param parameters
	 */
	protected void excuteSQL(String sql, List<?> parameters) {
		final String fSql=sql;
		final List<?> fParaments=parameters;
		getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)throws HibernateException, SQLException {
				Query query = session.createSQLQuery(fSql);
				if(fParaments!=null)
					for (int i = 0; i < fParaments.size(); i++) {
						query.setParameter(i, fParaments.get(i));
					}
				query.executeUpdate();
				return null;
			}
		});
	}
}
